# _*_ coding:utf-8 _*_
# @Time  : 2023.05.05
# @Author: zizlee
import re
from typing import List
import pandas as pd
from ast import literal_eval
from fastapi import APIRouter, Query, Depends, Body
from db_utils import BaseDatabaseConnection, IndexDataBaseConnection
from utils.jwt_token import TokenPayload
from utils.validate_util import DateRangeValidator
from utils.hutool_utils import DatlibUtils
from utils import datetime_utils
from response import APIResponse


class ExtraIndexItem(DateRangeValidator):
    extra_ids: List[int]


class GroupIndex:
    def __init__(self, group_id: int):
        self.gid = group_id

    # 获取一个组下的指标
    def get_group_index(self, payload: TokenPayload, group: int):
        # 目前只适用配置is_alone的
        with BaseDatabaseConnection() as conn:
            conn.cursor.execute("""
               SELECT id,name,is_alone,alone,is_formula,formula,is_stack,unit,user_id FROM datlib_group_index WHERE group_id=%s AND is_active=1 AND (user_id=0 OR user_id=%s)
               ORDER BY sort_num;
            """, [group, payload.user_id()])
            index_list = list(conn.cursor.fetchall())
            idx_ids = []
            for row in index_list:
                if row['is_alone']:
                    idx_ids.append(literal_eval(row['alone'])[0])
                if row['is_formula']:
                    idx_ids.extend(DatlibUtils.formula2ids(literal_eval(row['formula'])[0]))
            index_ids = list(set(idx_ids))
            if len(index_ids) < 1:
                return APIResponse.success(data={'data': []})
            # print(index_ids)
            # 查询指标具体信息
            conn.cursor.execute("SELECT id as iid,name,db_name,tb_name,frequency,unit,source,start_date,end_date FROM datlib_index WHERE id IN %s;", [index_ids])
            index_dict = {idx['iid']: idx for idx in list(conn.cursor.fetchall())}
        response_list = []
        for row in index_list:
            obj = None
            if row['is_alone']:
                iid = literal_eval(row['alone'])[0]
                obj = index_dict.get(iid)
                obj['is_private'] = row['user_id'] > 0
            if row['is_formula']:
                frm_exp = literal_eval(row['formula'])[0]
                frm_id_list = []
                for i in DatlibUtils.formula2ids(frm_exp):
                    _o = index_dict.get(i)
                    if _o:
                        frm_id_list.append(_o)
                start_date, end_date, frequency = DatlibUtils.public_date_range_frequency(index_objs=frm_id_list)
                obj = {
                    # 'id': row['id'],
                    'iid': None,  # 与创建时返回一致
                    # 'name': row['name'],
                    # 'unit': row['unit'],
                    'source': '',
                    'formula': frm_exp,
                    'start_date': start_date,
                    'end_date': end_date,
                    'frequency': frequency,
                    'is_private': row['user_id'] > 0
                }
            if obj:
                response_list.append({**row, **obj})

# {'id': 4439, 'name': '公共财政收入:当月同比', 'is_alone': True, 'alone': '(5462, "line")', 'is_formula': False,
#'is_stack': False, 'iid': 5462, 'db_name': 'ruizhi_db01', 'tb_name': 'wind_r00000005462',
# 'frequency': '月', 'unit': '%', 'source': '', 'start_date': '1990-01-31', 'end_date': '2023-06-30'}
        res_data = {
            'data': response_list
        }
        return APIResponse.success(data=res_data)


class GroupDataIndex:
    INTERVAL = 'INTERVAL'
    PAGINATOR = 'PAGINATOR'

    def __init__(self, group_index_id: int):
        self.giid = group_index_id

    @staticmethod
    def echarts_common_option(name, unit: str = ''):
        # color: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc']
        return {
            'title': {
                'text': name,
                'left': 'center',
                'top': 10,
            },
            'grid': {
                'top': 60,
                'bottom': 53,
            },
            'legend': {
                'type': 'scroll',
                'bottom': 7,
                'left': '10%'
            },
            'xAxis': {
                'type': 'category',
                'data': []
            },
            'yAxis': [
                {
                    'type': 'value',
                    'name': unit,
                    'scale': True
                },
                {
                    'type': 'value',
                    'name': unit,
                    'scale': True,
                    'splitLine': {'show': False}
                }
            ],
            'axisPointer': {
                'show': True
            },
            'series': [],
            'toolbox': {
                'show': True,
                'feature': {
                    'magicType': {
                        'type': ['line', 'bar'],
                        'title': {
                            'line': '切换为折线图',
                            'bar': '切换为柱状图',
                            'stack': '切换为堆叠',
                            'tiled': '切换为平铺'
                        }
                    },
                    'restore': {
                        'title': '还原'
                    },
                    'saveAsImage': {
                        'title': '保存为图片'
                    }
                }
            },
            'tooltip': {
                'trigger': 'axis',
                'showContent': True,
                'axisPointer': {
                    'type': 'cross',
                }
            },
        }

    @staticmethod
    def no_content_graphic(content='暂无数据'):
        return {
            'type': 'text',
            'left': 'center',
            'top': 'middle',
            'silent': True,
            'style': {
                'fill': '#9d9d9d',
                'fontWeight': 'bold',
                'text': content,
                'fontSize': '20px'
            }
        }

    @staticmethod
    def parse_formula(formula):
        iid_list = re.sub(r'[*/+-]', ',', re.sub(r'[()]', '', formula)).split(',')
        return [int(i.replace('i', '')) for i in iid_list]

    def _query_fact_index_list(self, ids: list):
        # 解析出数据指标并查询
        with BaseDatabaseConnection() as conn:
            conn.cursor.execute("SELECT id,name,is_alone,alone,is_formula,formula,unit FROM datlib_group_index WHERE id IN %s ORDER BY sort_num;", [ids])
            extra_list = list(conn.cursor.fetchall())
            index_id_list = self._parse_index_list(extra_list)
            conn.cursor.execute("""
                SELECT id,name,plat,plat_id,db_name,tb_name,frequency,unit,start_date,end_date FROM datlib_index WHERE id IN %s;
            """, [index_id_list])
            index_list = list(conn.cursor.fetchall())
        return index_list, extra_list

    def _parse_index_list(self, rows):
        index_list = []
        for r in rows:
            if r['is_alone']:
                index_list.append(literal_eval(r['alone'])[0])
            if r['is_formula']:
                formula_ids = DatlibUtils.formula2ids(formula=eval(r['formula'])[0])
                index_list.extend(formula_ids)
        return list(set(index_list))

    def _query_index_data(self, index_list, start_date=None, end_date=None):
        # 整理共同的库的指标
        db_indexes = {}
        for iid in index_list:
            iid['i_start'] = iid.get('start_date')
            iid['i_end'] = datetime_utils.now_yyyy_mm_dd()
            if iid.get('end_date'):
                iid['i_end'] = iid['end_date']
            if start_date:
                iid['i_start'] = start_date
            if end_date:
                iid['i_end'] = end_date
            db_indexes.setdefault(iid['db_name'], []).append(iid)
        index_data_list = []
        for db_name, index_list in db_indexes.items():
            with IndexDataBaseConnection(db_name=db_name) as conn:
                for o_idx in index_list:
                    o_data = conn.query_with_interval(tb_name=o_idx['tb_name'],
                                                      start_date=o_idx['i_start'], end_date=o_idx['i_end'],
                                                      ascending=False)
                    index_data_list.append({**o_idx, 'data': o_data})
        return index_data_list

    def _format_index_data(self, data_list, extra_list=()):
        ret_df = None
        table_columns = []
        for i, dt in enumerate(data_list):
            tmp = pd.DataFrame(dt['data']['rows'])
            if tmp.empty:
                continue
            value_col = f'col_{i}'
            tmp.rename(columns={'datavalue': value_col}, inplace=True)
            table_columns.append({'id': dt['id'], 'prop': value_col, 'label': dt['name'], 'frequency': dt['frequency'], 'unit': dt['unit'],
                                  'start_date': dt['start_date'], 'end_date': dt['end_date']})
            del tmp['id']
            if ret_df is None:
                ret_df = tmp
                continue
            ret_df = pd.merge(ret_df, tmp, how='outer', on='datadate')
        if ret_df is None:
            return ret_df, table_columns
        ret_df.sort_values(by='datadate', inplace=True, ascending=False)
        # print(ret_df)

        # 公式计算并整理返回的数据
        prop_kv = {}
        fre_kv = {}
        cols_kv = {}
        for col in table_columns:
            prop_kv[f'i{col["id"]}'] = col['prop']
            fre_kv[f'i{col["id"]}'] = col['frequency']
            cols_kv[col['id']] = col

        exp_index = 0  # 公式的列名索引
        exp_fre_list = []  # 可能的频率值
        response_columns = []  # 返回的表格列字段
        for ext in extra_list:
            if ext['is_alone']:
                kid = eval(ext['alone'])[0]
                response_columns.append(cols_kv[kid])
            if ext['is_formula']:
                frequency = ''
                src_exp = eval(ext['formula'])[0]
                for k, v in prop_kv.items():
                    if src_exp.find(k) > -1:
                        exp_fre_list.append(fre_kv[k])
                    src_exp = src_exp.replace(k, v)
                exp_col_name = f'exp_{exp_index}'
                ret_df.eval(f'{exp_col_name} = {src_exp}', inplace=True)  # pandas计算
                ret_df[exp_col_name] = ret_df[exp_col_name].apply(lambda x: round(x, 2))
                for f in ['日', '周', '月', '季', '年']:
                    if f in exp_fre_list:
                        frequency = f
                        break

                response_columns.append({
                    'prop': f'exp_{exp_index}',
                    'label': ext['name'],
                    'frequency': frequency,
                    'unit': ext['unit']
                })
                exp_index += 1
        ret_df.fillna('', inplace=True)
        return ret_df, response_columns

    # 获取某个指标的具体数据
    def get_group_index_detail_data(self, start: str = None, end: str = None,
                                    page: int = 1, page_size: int = 100):
        start_date, end_date = (None, None)
        if start:
            start_date = datetime_utils.auth_yyyymmdd(start, obj=True)
        if end:
            end_date = datetime_utils.auth_yyyymmdd(end, obj=True)

        # 查询指标详情信息
        with BaseDatabaseConnection() as conn:
            conn.cursor.execute("SELECT * FROM datlib_group_index WHERE id=%s LIMIT 1;", [self.giid])
            gi_obj = conn.cursor.fetchone()
            if not gi_obj:
                return None, None
            # 分别解析出在datlib_index中的id
            if gi_obj['is_alone']:
                iid_list = [int(literal_eval(gi_obj['alone'])[0])]
            elif gi_obj['is_formula']:
                formula_expression, _ = literal_eval(gi_obj['formula'])
                iid_list = self.parse_formula(formula_expression)
            elif gi_obj['is_stack']:
                iid_list = [s[1] for s in literal_eval(gi_obj['stack'])]
            else:
                return None, None
            # 查询具体表数据
            conn.cursor.execute("""
                SELECT id,name,plat,plat_id,db_name,tb_name,frequency,unit,start_date,end_date,state
                FROM datlib_index WHERE id IN (%s);
            """ % ','.join([str(i) for i in iid_list])
                                )
            iid_detail_list = list(conn.cursor.fetchall())
        # 分组指标
        db_indexes = {}
        for iid in iid_detail_list:
            db_indexes.setdefault(iid['db_name'], []).append(iid)
        # 查询具体的指标数据
        detail_data = []
        value_start, value_end = (None, None)
        chart_start, chart_end = (None, None)
        for db_name, index_list in db_indexes.items():
            with IndexDataBaseConnection(db_name=db_name) as conn:
                for o_idx in index_list:
                    if value_start is None or o_idx['start_date'] > value_start:
                        value_start = o_idx['start_date']
                    if value_end is None or o_idx['end_date'] < value_end:
                        value_end = o_idx['end_date']

                    if all([start_date, end_date]):  # 有日期,使用日期查询
                        sdt = datetime_utils.to_yyyy_mm_dd(start_date)
                        edt = datetime_utils.to_yyyy_mm_dd(end_date)
                        ret = conn.query_with_interval(o_idx['tb_name'], start_date=sdt, end_date=edt)
                        o_idx['data'] = ret
                        o_idx['ret_type'] = self.INTERVAL
                    else:  # 使用分页查询
                        ret = conn.query_with_paginator(o_idx['tb_name'], page=page, page_size=page_size,
                                                        ascending=False)
                        o_idx['data'] = ret
                        o_idx['ret_type'] = self.PAGINATOR

                    if chart_start is None or (ret['start_date'] and ret['start_date'] > chart_start):
                        chart_start = ret['start_date']
                    if chart_end is None or (ret['end_date'] and ret['end_date'] < chart_end):
                        chart_end = ret['end_date']

                    detail_data.append(o_idx)

        gi_obj['start_date'] = value_start
        gi_obj['end_date'] = value_end
        gi_obj['chart_start'] = chart_start
        gi_obj['chart_end'] = chart_end
        return gi_obj, detail_data

    # 获取一个指标的具体数据
    def group_index_detail(self, start: str = None, end: str = None,
                           page: int = 1, page_size: int = 100):
        gi_obj, detail_data = self.get_group_index_detail_data(start=start, end=end, page=page,
                                                               page_size=page_size)
        # 提取具体数据
        if gi_obj['is_alone']:
            index_id, chart_type = literal_eval(gi_obj['alone'])
            dd_dict = {dat['id']: dat for dat in detail_data}
            detail_data = dd_dict.get(int(index_id), {})
        elif gi_obj['is_formula']:
            formula_expression, _ = literal_eval(gi_obj['formula'])
            df = self.parse_formula_data(formula_expression=formula_expression, detail_data=detail_data)
            if df.empty:
                detail_data = {}
            else:
                detail_data = {
                    'id': -1,
                    'name': gi_obj['name'],
                    'data': {
                        'rows': df.to_dict(orient='records'),
                        'start_date': None,
                        'end_date': None
                    }
                }
        elif gi_obj['is_stack']:
            detail_data = {}
        else:
            detail_data = {}
        return APIResponse.success(data={'detail': detail_data, 'description': gi_obj})

    # 提取一个或多个指标数据
    def extra_index_data(self, payload: TokenPayload, extra_item: ExtraIndexItem):
        if len(extra_item.extra_ids) < 1:
            return APIResponse.success(data={'table_data': [], 'table_columns': []})
        index_list, extra_list = self._query_fact_index_list(extra_item.extra_ids)
        if len(index_list) < 1:
            return APIResponse.success(data={'table_data': [], 'table_columns': []})
        index_data = self._query_index_data(index_list)  # 得到具体指标的数据
        # 合并成表格数据
        df, columns = self._format_index_data(index_data, extra_list)
        if df is None:
            df = pd.DataFrame()
        return APIResponse.success(data={'table_data': df.to_dict(orient='records'), 'table_columns': columns})

    # 获取一个指标的具体图形配置
    def group_index_chart_option(self, start: str = None, end: str = None,
                                 page: int = 1, page_size: int = 100):
        gi_obj, detail_data = self.get_group_index_detail_data(start=start, end=end, page=page, page_size=page_size)
        if not gi_obj:
            return APIResponse.no_content(msg='查询成功，不存在该指标数据!')
        # 生成echarts图形配置
        if gi_obj['is_alone']:
            option = self._get_alone_chart_option(gi_obj=gi_obj, detail_data=detail_data)
        elif gi_obj['is_formula']:
            option = self._get_formula_chart_option(gi_obj=gi_obj, detail_data=detail_data)
        elif gi_obj['is_stack']:
            option = self._get_stack_chart_option(gi_obj=gi_obj, detail_data=detail_data)
        else:
            option = self.echarts_common_option(name='查询无数据')
        return APIResponse.success(data={'option': option, 'description': gi_obj})

    # 获取堆叠图形配置
    def group_index_chart_option_stack(self, payload: TokenPayload, giid: str, year: int = 3, start: str = None, end: str = None):
        index_list, extra_list = self._query_fact_index_list(ids=giid.split(','))
        if len(index_list) < 1:
            return APIResponse.success(data={'data': [], 'option': self.no_content_graphic()})
        start_date = datetime_utils.auth_yyyy_mm_dd(start)
        end_date = datetime_utils.auth_yyyy_mm_dd(end)
        if year > 0:
            start_year = int(datetime_utils.now_yyyy_mm_dd()[0:4]) - year
            start_date, end_date = f'{start_year}-01-01', datetime_utils.now_yyyy_mm_dd()
        index_data = self._query_index_data(index_list, start_date=start_date, end_date=end_date)
        # 合并成表格数据
        df, columns = self._format_index_data(index_data, extra_list=extra_list)
        chart_name = ','.join([c['label'] for c in columns])
        if len(chart_name) > 20:
            chart_name = chart_name[:20] + '...'
        unit = columns[0]['unit'] if len(columns) == 1 else ''
        opt = self.echarts_common_option(name=chart_name, unit=unit)
        if df is None or df.empty or len(columns) < 1:
            opt['graphic'] = self.no_content_graphic()
            return APIResponse.success(data={'data': [], 'option': opt})
        # 生成图形配置
        df.sort_values(by='datadate', ascending=True, inplace=True)
        x_axis_data = df['datadate'].tolist()
        series_data = []
        for c in columns:
            series_data.append({
                'name': c['label'],
                'type': 'line',
                'yAxisIndex': 0,
                'data': df[c['prop']].tolist(),
                'symbol': 'none',
                'connectNulls': True
            })
        opt['xAxis']['data'] = x_axis_data
        opt['series'] = series_data
        return APIResponse.success(data={'data': columns, 'option': opt})

    # 季节图形
    def group_index_chart_option_season(self, year: int = 3):  # 默认查近3年
        start_year = int(datetime_utils.now_yyyy_mm_dd()[0:4]) - year
        start_date, end_date = f'{start_year}0101', datetime_utils.now_yyyymmdd()
        gi_obj, detail_data = self.get_group_index_detail_data(start=start_date, end=end_date)
        if not gi_obj:
            return APIResponse.no_content(msg='查询的指标不存在.')
        opt = self.echarts_common_option(name=gi_obj['name'] + '季节分析', unit=gi_obj['unit'])
        if len(detail_data) < 1:
            opt['graphic'] = self.no_content_graphic()
            return APIResponse.success(data={'data': gi_obj, 'option': opt})

        if detail_data[0]['frequency'] in ['季', '年']:
            opt['graphic'] = self.no_content_graphic(content='该指标不适用季节分析')
            return APIResponse.success(data={'data': gi_obj, 'option': opt})

        # 按不同年份分组
        dd = dict()
        for row in detail_data[0]['data']['rows']:
            row['date'] = row['datadate'][-5:]
            dd.setdefault(row['datadate'][0:4], []).append(row)
        if len(dd) < 1:
            opt['graphic'] = self.no_content_graphic(content=f'无近{year}年数据')
            return APIResponse.success(data={'data': gi_obj, 'option': opt})
        x_axis_data = datetime_utils.generate_dates_of_year()
        series_data = []
        for y, y_rows in dd.items():
            y_values = {r['date']: r['datavalue'] for r in y_rows}
            series_data.append({
                'name': str(y),
                'type': 'line',
                'yAxisIndex': 0,
                'data': [y_values.get(x) for x in x_axis_data],
                'showSymbol': False,
                'connectNulls': True
            })
        opt['xAxis']['data'] = x_axis_data
        opt['xAxis']['axisLabel'] = {
            'showMaxLabel': True
        }
        opt['series'] = series_data
        return APIResponse.success(data={'data': gi_obj, 'option': opt})

    # 区间图形
    def group_index_chart_option_interval(self, year: int = 3):
        start_year = int(datetime_utils.now_yyyy_mm_dd()[0:4]) - year
        start_date, end_date = f'{start_year}0101', datetime_utils.now_yyyymmdd()
        gi_obj, detail_data = self.get_group_index_detail_data(start=start_date, end=end_date)
        if not gi_obj:
            return APIResponse.no_content(msg='查询成功，不存在该指标数据!')
        opt = self.echarts_common_option(name=gi_obj['name'] + '区间分析', unit=gi_obj['unit'])
        if len(detail_data) < 1:
            opt['graphic'] = self.no_content_graphic()
            return APIResponse.success(data={'data': gi_obj, 'option': opt})

        if detail_data[0]['frequency'] in ['月', '季', '年']:
            opt['graphic'] = self.no_content_graphic(content='该指标不适用区间分析')
            return APIResponse.success(data={'data': gi_obj, 'option': opt})
        opt['grid']['left'] = '5%'
        opt['grid']['right'] = '5%'
        x_axis_data = datetime_utils.generate_dates_of_year()
        date_df = pd.DataFrame(x_axis_data, columns=['date'])
        df = pd.DataFrame(detail_data[0]['data']['rows'])
        if df.empty:
            opt['graphic'] = self.no_content_graphic(content=f'无近{year}年数据')
            return APIResponse.success(data={'data': gi_obj, 'option': opt})
        df['year'] = df['datadate'].apply(lambda a: a[0:4])
        df['date'] = df['datadate'].apply(lambda a: a[-5:])
        cur_year = datetime_utils.now_yyyymmdd()[0:4]
        to_cul_df = df[df['year'] <= cur_year].copy()  # 计算的数据小于当前年份
        cur_df = df[df['year'] == cur_year].copy()  # 当前年度数据
        del df
        # 以年分组,循环每个dataframe,处理后横向拼接
        temp_df = pd.DataFrame()
        for year in to_cul_df.groupby(by=['year'], as_index=False).groups:
            year_df = to_cul_df[to_cul_df['year'] == year]
            year_df = pd.merge(year_df, date_df, on='date', how='outer')  # 横向拼接
            year_df.sort_values(by=['date'], inplace=True)  # 排序
            year_df.fillna(method='ffill', inplace=True)  # 使用上值填充NAN
            year_df.fillna(method='bfill', inplace=True)  # 使用下方第一个非NAN填充(补充开年几天的数值)
            if year == str(cur_year):  # 当前年
                year_df = year_df[year_df['date'] <= gi_obj['end_date'][-5:]]  # 当前年取到有数据的日期
            temp_df = pd.concat([temp_df, year_df])  # 竖向拼接
        temp_df.sort_values(by=['year', 'date'], inplace=True)  # 排序
        min_df = temp_df.groupby(by=['date'], as_index=False)['datavalue'].min()
        max_df = temp_df.groupby(by=['date'], as_index=False)['datavalue'].max()
        mean_df = temp_df.groupby(by=['date'], as_index=False)['datavalue'].mean()

        # 横向拼接
        ret_df = pd.merge(min_df, max_df, on='date')
        ret_df.columns = ['date', 'min', 'max']
        ret_df = pd.merge(ret_df, mean_df, on='date')
        ret_df.columns = ['date', 'min', 'max', 'mean']

        ret_df = pd.merge(ret_df, cur_df[['date', 'datavalue']], on='date', how='left')  # 拼入当前年度数据
        ret_df['mean'] = ret_df['mean'].apply(lambda b: round(b, 2))
        ret_df['fake_max'] = ret_df.apply(lambda v: v['max'] - v['min'], axis=1)
        ret_df['fake_max'] = ret_df['fake_max'].apply(lambda v: round(v, 2))
        ret_df.fillna(method='ffill', inplace=True)  # 使用上值填充NAN
        ret_df.fillna(method='bfill', inplace=True)  # 使用下方第一个非NAN填充(补充开年几天的数值)
        ret_df.fillna('-', inplace=True)  # 整列都不存在数据时问题
        ret_df['datavalue'] = ret_df['datavalue'].mask(ret_df['date'] > gi_obj['end_date'][-5:], '-')  # 当前年度大于今日的数据处理
        opt['series'] = [
            {
                # 'name': '最小值',
                'type': 'line',
                'stack': 'total',
                'color': '#aaaaaa',
                'symbol': 'none',
                'connectNulls': True,
                # 'areaStyle': {'color': '#dddddd'},
                'data': ret_df['min'].tolist()
            },
            {
                # 'name': '最大值',
                'type': 'line',
                'stack': 'total',
                'color': '#aaaaaa',
                'areaStyle': {'color': '#dddddd'},
                'symbol': 'none',
                'connectNulls': True,
                'data': ret_df['fake_max'].tolist()
            },
            {
                'name': '均值',
                'type': 'line',
                'symbol': 'none',
                'connectNulls': True,
                'data': ret_df['mean'].tolist()
            },
            {
                'name': '当前值',
                'type': 'line',
                'symbol': 'none',
                'connectNulls': True,
                'lineStyle': {'color': '#ee6666'},
                'itemStyle': {'color': '#ee6666'},
                'z': 9,
                'data': ret_df['datavalue'].tolist()
            }
        ]
        opt['xAxis']['data'] = x_axis_data
        opt['xAxis']['axisLabel'] = {
            'showMaxLabel': True
        }
        return APIResponse.success(data={'data': gi_obj, 'option': opt})

    def _get_stack_chart_option(self, gi_obj, detail_data):
        dd_dict = {dat['id']: dat for dat in detail_data}
        opt = self.echarts_common_option(name=gi_obj['name'], unit=gi_obj['unit'])
        x_axis_data = []
        series_data = []
        for st in literal_eval(gi_obj['stack']):
            y_pos, index_id, chart_type = st  # st：(轴位置,指标ID,图形类型)
            dd = dd_dict.get(index_id)
            if not dd or len(dd['data']['rows']) < 1:
                continue
            dd_values = {dv['datadate']: dv['datavalue'] for dv in dd['data']['rows']}
            if len(x_axis_data) == 0:
                x_axis_data = sorted([dt['datadate'] for dt in dd['data']['rows']])
                opt['xAxis']['data'] = x_axis_data
            if y_pos == 1 and len(opt['yAxis']) < 2:
                opt['yAxis'].append({'type': 'value', 'name': dd['unit'], 'scale': True})
            if not opt['yAxis'][0]['name']:
                opt['yAxis'][0]['name'] = dd['unit']
            series_data.append({
                'name': dd['name'],
                'type': chart_type,
                'yAxisIndex': y_pos,
                'data': [dd_values.get(d) for d in x_axis_data],
                'symbol': 'none'
            })
        if len(series_data) < 1:
            opt['graphic'] = self.no_content_graphic()
        opt['series'] = series_data
        return opt

    def _get_formula_chart_option(self, gi_obj, detail_data):
        formula = literal_eval(gi_obj['formula'])
        formula_expression, chart_type = formula
        df = self.parse_formula_data(formula_expression=formula_expression, detail_data=detail_data)
        opt = self.echarts_common_option(name=gi_obj['name'], unit=gi_obj['unit'])
        if df.empty:
            opt['graphic'] = self.no_content_graphic()
            return opt
        opt['xAxis']['data'] = df['datadate'].tolist()
        opt['series'] = [{
            'name': gi_obj['name'],
            'type': chart_type,
            'yAxisIndex': 0,
            'data': df['datavalue'].tolist(),
            'symbol': 'none'
        }]
        return opt

    def parse_formula_data(self, formula_expression, detail_data):
        iid_list = self.parse_formula(formula=formula_expression)
        dd_dict = {dat['id']: dat for dat in detail_data}
        df = pd.DataFrame()
        for iid in iid_list:
            dd = dd_dict.get(iid)
            if not dd or len(dd['data']['rows']) < 1:
                continue
            new_df = pd.DataFrame(dd['data']['rows'])
            new_df.rename(columns={'datavalue': f'i{iid}'}, inplace=True)
            del new_df['id']
            if df.empty:
                df = new_df
            else:
                df = pd.merge(df, new_df, on='datadate')
        if df.empty:
            return df
        df.eval(f'datavalue = {formula_expression}', inplace=True)  # 计算结果值
        df.sort_values(by='datadate', inplace=True)
        return df

    def _get_alone_chart_option(self, gi_obj, detail_data):
        index_id, chart_type = literal_eval(gi_obj['alone'])
        dd_dict = {dat['id']: dat for dat in detail_data}
        dd = dd_dict.get(int(index_id))
        opt = self.echarts_common_option(name=gi_obj['name'], unit=gi_obj['unit'])
        if not dd or len(dd['data']['rows']) < 2:
            opt['graphic'] = self.no_content_graphic()
            return opt
        x_axis_data = sorted([dt['datadate'] for dt in dd['data']['rows']])
        dd_values = {dv['datadate']: dv['datavalue'] for dv in dd['data']['rows']}
        opt['xAxis']['data'] = x_axis_data
        opt['series'] = [{
            'name': dd['name'],
            'type': chart_type,
            'yAxisIndex': 0,
            'data': [dd_values.get(d) for d in x_axis_data],
            'showSymbol': False,
            'emphasis': {
                'itemStyle': {
                    'color': '#5470c6',
                    'borderWidth': 1
                }
            },
        }]
        return opt


group_index_api = APIRouter()


@group_index_api.get('/indexList/')  # 获取组下的指标列表
def get_group_index(payload: TokenPayload = Depends(TokenPayload), group: int = Query(...)):
    return GroupIndex(group_id=group).get_group_index(payload=payload, group=group)


# @group_index_api.get('/indexDetail/')  # 获取一个指标的详细数据giid=group index id(整改后没用了)
def get_index_chart_detail(giid: int = Query(...),
                           start: str = Query(None), end: str = Query(None),
                           page: int = Query(1), page_size: int = Query(100, le=100)):
    return GroupDataIndex(group_index_id=giid).group_index_detail(start=start, end=end,
                                                                  page=page, page_size=page_size)


@group_index_api.post('/extradb/')  # 提取一个或多个指标数据
def extra_index_data(payload: TokenPayload = Depends(TokenPayload), extra_item: ExtraIndexItem = Body(...)):
    return GroupDataIndex(group_index_id=-1).extra_index_data(payload=payload, extra_item=extra_item)


# @group_index_api.get('/chartOption/')  # 获取一个指标的图形配置giid=group index id
def get_index_chart_option(giid: int = Query(...),
                           start: str = Query(None), end: str = Query(None),
                           page: int = Query(1), page_size: int = Query(100, le=100)):
    return GroupDataIndex(group_index_id=giid).group_index_chart_option(start=start, end=end,
                                                                        page=page, page_size=page_size)


@group_index_api.get('/chartOptionStack/')  # 获取多个指标堆叠图形
def get_index_chart_option_stack(payload: TokenPayload = Depends(TokenPayload), giid: str = Query(...), year: int = Query(3),
                                 start: str = Query(None), end: str = Query(None)):
    return GroupDataIndex(group_index_id=-1).group_index_chart_option_stack(payload=payload, giid=giid, year=year, start=start, end=end)


@group_index_api.get('/chartOptionSeason/')  # 获取一个数据指标的季节图
def get_index_chart_option_season(giid: int = Query(...), year: int = Query(3)):
    return GroupDataIndex(group_index_id=giid).group_index_chart_option_season(year)


@group_index_api.get('/chartOptionInterval/')  # 区间分析图形
def get_index_chart_option_interval(giid: int = Query(...), year: int = Query(3)):
    return GroupDataIndex(group_index_id=giid).group_index_chart_option_interval(year=year)

